const axios = require("axios");

// token加密解密
const jwt = require("jsonwebtoken");
const PRIVATE_KEY = "21tM#i&Ak1_t5a";

// 数据库
require("./db");
const Users = require("./db/models/users");

// 文件上传
const multer = require("multer");

const storage = multer.diskStorage({
  // 上传文件存储位置
  destination: function (req, file, cb) {
    cb(null, "./public/images");
  },
  // 上传文件如何命名
  filename: function (req, file, cb) {
    cb(null, file.originalname);
  },
});

const upload = multer({ storage: storage });

// 服务器
const express = require("express");
const app = express();

// 登录小程序管理平台
// 开发管理 - 开发设置
const APP_ID = "wx3928e5f699a4539f";
const APP_SECRET = "53c6a6efb5e77e1cce8b85009aabf804";

// 生成随机用户名
const generateNickname = () => {
  return (
    "u_" +
    (Number(Math.random().toString().substring(2)) + Date.now()).toString(32)
  );
};

// 搭建路由或中间件
// 配置静态资源中间件
app.use(express.static("./public"));
// 解析请求体数据
app.use(express.json());

// 授权登录
app.get("/login-auth", async (request, response) => {
  /*
    request req 请求对象（包含所有请求信息：客户端发送给服务器的数据）
      query    req.query
      params   req.params(配合路由占位符一起使用：/xxx/:id)
      body     req.body
      headers  req.headers
      cookie   req.headers.cookie / (使用一个中间件cookie-parser解析cookie) req.cookies

    response res 响应对象（包含所有响应信息：服务器发送给客户端的数据）
      headers  res.headers
      body     
        res.send() 用来响应纯文本数据
        res.json() 用来响应json数据
      status
        res.status() 设置响应状态码
  */

  // 获取客户端发送的code
  const { code } = request.query;

  // 通过 三个参数 向微信服务器发送请求，得到用户的openid
  // https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
  const res = await axios.get("https://api.weixin.qq.com/sns/jscode2session", {
    params: {
      appid: APP_ID,
      secret: APP_SECRET,
      js_code: code,
      grant_type: "authorization_code",
    },
  });

  const { openid, session_key } = res.data;

  const user = await Users.findOne({ openid });

  if (!user) {
    // 将openid存储起来
    await Users.create({
      openid,
      nickname: generateNickname(),
    });
  }

  // 通过jwt生成token
  const token = jwt.sign(
    {
      openid,
    },
    PRIVATE_KEY,
    {
      expiresIn: "7d",
    }
  );

  // 将token响应给小程序
  response.json({
    code: 200,
    message: "",
    success: true,
    data: token,
  });
});
// 获取用户信息
app.get("/getUserInfo", async (req, res) => {
  const token = req.headers.token;
  try {
    const { openid } = jwt.verify(token, PRIVATE_KEY);
    const user = await Users.findOne({ openid }, { _id: 0, __v: 0, openid: 0 });
    res.json({
      code: 200,
      message: "",
      success: true,
      data: user,
    });
  } catch {
    res.json({
      code: 201,
      message: "未登录",
      success: false,
      data: null,
    });
  }
});

// 上传
app.post("/upload", upload.single("avatar"), (req, res) => {
  res.json({
    code: 200,
    data: "http://localhost:5000/images/" + req.file.originalname,
  });
});

// 默认是不解析请求体数据的，需要使用中间件
app.put("/setUserInfo", async (req, res) => {
  const { nickname, avatar } = req.body;
  const { token } = req.headers;
  try {
    const { openid } = jwt.verify(token, PRIVATE_KEY);
    await Users.updateOne(
      { openid },
      {
        $set: {
          nickname,
          avatar,
        },
      }
    );
    res.json({
      code: 200,
      data: null,
    });
  } catch {
    res.json({
      code: 201,
      data: null,
      message: "修改失败",
    });
  }
});

// 启动服务器
app.listen(5000, "localhost", (err) => {
  // 错误优先机制（回调函数的第一个参数往往都是错误对象）
  if (err) console.log(err);
  else console.log("服务器启动成功了, http://localhost:5000");
});
